#ifndef __CLIENTFUNC__
#define __CLIENTFUNC__

#include "54func.h"
#define TRAINLEN 1000
#define TOKENLEN 512
#define ARGVLEN 256

// 结构体定义
// 全局变量结构体,标识目前是否有用户登录以及用户名
typedef struct loginInfo_s                                                                                                                         
{     
    int loginFlag;      // 0:无人登录 1:有人登录
    char userName[20];  // 无人登录时全为0,有人登录时保存对应用户名
    char token[TOKENLEN];
} loginInfo_t;

// 服务端地址结构体变量，用于创建子线程的socket
typedef struct{
    char ip[20];
    char port[10];
} addrInfo_t;

// 存储cmd及参数的结构体
typedef struct {
    char cmdToken[8];
    char user[20];
    char token[TOKENLEN];
    int argc;
    char argv1[ARGVLEN];
    char argv2[ARGVLEN];
} cmd_t;

// cwd栈的结点(双向链表)
typedef struct pathToken_s{
    char data[255];
    struct pathToken_s *pfront; 
    struct pathToken_s *pnext; 
} pathToken_t;

// cwd栈
typedef struct {
    pathToken_t *top;
    pathToken_t *bottom;
    int size;
} cwd_t;

// 小火车
typedef struct train_s
{
    int length;
    char data[TRAINLEN];
} train_t;


//全局变量
extern loginInfo_t loginInfo;
extern addrInfo_t addrInfo;
extern cwd_t cwd;

// cwd的操作函数
// cwd栈出栈
int pop(cwd_t *pcwd);
// cwd栈入栈
int push(cwd_t *pcwd,const char *data);
// 清除所有目录栈
int clear(cwd_t *pcwd);
// 处理当前的token，对cwd进行相应的出栈入栈
int cwdCtl(cwd_t *pcwd, char* token);
// 真拷贝整个栈
int cwdCpy(cwd_t* pcwdSrc, cwd_t* pcwdCpy);
// 销毁整个栈
int destoryCwd(cwd_t* pcwd);
// 通过传入的虚拟地址，修改cwd栈的结构
int parsePath(cwd_t *pcwd, char* virtualPath);
// 取出cwd栈中所存的路径, pwdstr用于存储路径
int getPath(const cwd_t *pcwd, char *pwdstr);
// 根据传入的路径(cmd_t结构体中的一个argv字符串,可相对可绝对)
// 获取一个数据库目录系统的绝对路径
int realServerPath(cwd_t* pcwd, char* argv);

// 辅助函数
// 判断路径是否和传入类型匹配
// 传入S_IFREG(普通文件)或S_IFDIR(目录)判断类型
int pathJudge(const char* realPath, mode_t mode);
// recvn
int recvn(int sockfd, void *buf, int length);
// 根据传入的路径(cmd_t结构体中的一个argv字符串,可相对可绝对)
// 获取真实的Linux绝对路径存入realPath中
int realPath(const char *argv, char *realPath);
// 接收确认信息'e'或'o', 信息为'o'时返回1, 为'e'时读取报错信息并打印, 返回0
int recvMsg(int sockfd, train_t* ptrain);
// 用小火车发送字符串
int strSend(int sockfd, train_t* ptrain, const char* str);
// 发送成功信息'o'
int successSend(int sockfd);
// 发送错误信息, 如果填入NULL, 发送一个'e'报错信号
// 如果填入字符串, 将其作为报错信息发送给客户端
int errorSend(int sockfd, const char* errorMsg);
// 如果是puts指令，调用以下函数计算sha1值并发送
int sha1Send(int sockfd, const char *fileName);


// 解析指令+上传指令,返回0表示指令解析正确
int parseToken(char *command, cmd_t *pcmd);
// 接收服务端返回值+相应处理(调用puts+gets)
int cmdClientHandler(int sockfd, cmd_t *pcmd);

// 指令函数
// 处理pwd指令的返回值
int pwdProc(const cwd_t* pcwd);
// 处理cd指令的返回值
int cdProc(int sockfd, cwd_t* pcwd, cmd_t* pcmd);
// 处理ls指令的返回值
int lsProc(int sockfd, cwd_t* pcwd, cmd_t* pcmd);
// 处理rm指令的返回值
int rmProc(int sockfd, cwd_t* pcwd, cmd_t* pcmd);
// 处理mkdir指令的返回值
int mkdirProc(int sockfd, cwd_t* pcwd, cmd_t* pcmd);

// 创建用于上传下载的子线程
int makeTransRequest(cmd_t* pcmd);
// 上传文件
int clientPuts(int sockfd, cwd_t* pcwd, cmd_t *pcmd);
// 下载文件
int clientGets(int sockfd, cmd_t *pcmd);

// 处理login指令的S返回值
int userLoginProc(int sockfd, const cmd_t* pcmd);
// 处理logout指令的S返回值
int userLogoutProc();
// 处理userAdd指令的S返回值
int userAddProc(int sockfd, const cmd_t* pcmd);
// 处理userAdd指令的S返回值
int userDelProc(int sockfd, const cmd_t* pcmd);

#endif
